(ns ca.uoit.molly.molly-search
  (:require [ca.uoit.molly.lucene-molly :as lucene-molly]
            [ca.uoit.molly.lucene-helper :as lucene])
  (:use [clojure.contrib.str-utils]))

(def *value-searcher* (lucene/mk-index-searcher "mycampus-value.idx"))
(def *entity-searcher* (lucene/mk-index-searcher "mycampus-entity.idx"))
(def *group-searcher* (lucene/mk-index-searcher "mycampus-group.idx"))

(defn search-values
  "(search-values {:phrase 'hello world'})"
  [{:keys [phrase topk idx]}]
  (let [qry (apply lucene/mk-query
              (for [t (lucene/analyze-str
                       lucene/*default-analyzer*
                       (lucene-molly/ngram-str phrase))]
              {:f "__all__" :v t :or true}))]
    (map lucene-molly/doc-to-value (lucene/index-search idx qry topk))))

(defn search-entities
  "(search-entities 
    {:entity 'person'
     :id '10023' 
     :attrs [{:name 'first' :value 'ken'} {:name 'last' :value 'pu'}]
     :phrases ['what is the name' 'database' 'programming']})"
  [{:keys [entity id attrs phrases idx topk debug] :as args}]
  (let [q0 (if (nil? entity)
            []
            [{:f "__entity__" :v entity :or false}])
        q1 (if (nil? id)
            []
            [{:f "__id__" :v id :or false}])
        phrase (str-join " " phrases)
        q2 (for [t (lucene/analyze-str lucene/*default-analyzer* phrase)]
             {:f "__all__" :v t :or true})
        q3 (flatten
             (for [v attrs] 
               (for [t (lucene/analyze-str 
                          lucene/*default-analyzer*
                          (:value v))]
                  {:f (name (:name v)) :v t})))
        q (clojure.set/union q0 q1 q2 q3)
        qry (apply lucene/mk-query q)]
    (when debug (println "DEBUG: query is " q))
    (map lucene-molly/doc-to-entity (lucene/index-search idx qry topk))))

(defn search-groups
  "(search-group
    {:entities [{:entity 'course' :id 'csci 2020u'}
                {:entity 'person' :id '10234'}]
     :attrs [{:name 'last' :value 'pu'}]
     :parameters [{:name 'semester' :value '2011'}]
    })"
  [{:keys [entities attrs parameters idx analyzer topk debug] :as args}]
  (let [
    ;
    ; Searching the entity nodes
    ;
    q0 (for [ent entities] 
         {:f "__nodes__" :v (lucene-molly/encode-node ent)})
    ;
    ; Searching the parameters
    ;
    q1 (flatten
         (for [param parameters]
            (for [t (lucene/analyze-str lucene/*default-analyzer*
                      (str (:name param) " " (:value param)))]
              {:f "__param__" :v t})))
    ;
    ; Searching the attributes: we perform entity search on the attributes
    ; and then use these entities to search for groups
    ;
    q2 (if (nil? attrs)
         []
         (for [ent (search-entities
                    {:idx *entity-searcher* ; TODO: hardcoded
                     :topk 3   ; this is a parameter
                     :attrs attrs
                     :debug debug})]
          {:f "__nodes__" :v (lucene-molly/encode-node ent)}))
    ;
    ;
    ; TODO: we do not support phrase search YET.
    ;
    q (clojure.set/union q0 q1 q2)
    qry (apply lucene/mk-query q)]
    (when debug (println "DEBUG: query is " q))
    (map lucene-molly/doc-to-denorm-group 
      (lucene/index-search idx qry topk))))
